#ifndef __APPLI_CORE_ALE_NS_H
#define __APPLI_CORE_ALE_NS_H 1

#include <feel/options.hpp>
#include <feel/feelcore/application.hpp>

#include <MecaFluide/mecafluide.hpp>
#include <MecaSolGrandeDef/StVenKir.hpp>

//#include <cldata.hpp>

namespace Feel
{


    class Aitken
    {
    public :

        typedef double value_type;
        typedef Backend<value_type> backend_type;
        typedef boost::shared_ptr<backend_type> backend_ptrtype;
        typedef /*typename*/ backend_type::vector_ptrtype vector_ptrtype;

        Aitken(backend_ptrtype __backend,vector_ptrtype uuu)
            :
            M_backend(__backend),
            M_w(1.),
            M_mu(0.),
            M_imax(0),
            M_isFirstExperience(true),
            M_u_i(__backend->newVector( uuu->map() ) ),
            M_u_im1(__backend->newVector( uuu->map() ) )
        {}

        template <typename elemtype>
        void
        //updateParameter(uint __i,vector_ptrtype __u_ip1)
        updateParameter(uint __i, elemtype __u_ip1)
        {
            vector_ptrtype u_ip1(M_backend->newVector( M_u_i->map() ));
            u_ip1->zero();
#if 0
            modifVec222(*__u_ip1,u_ip1, vf::idv(*__u_ip1) , "Interieur" );
#else
            *u_ip1 = *__u_ip1;
#endif
            if (!M_isFirstExperience)
                {
                    vector_ptrtype delta_u_i(M_backend->newVector( M_u_i->map() ));
                    delta_u_i->zero();
                    delta_u_i->add(1.,M_u_im1);
                    delta_u_i->add(-1.,M_u_i);

                    vector_ptrtype delta_u_ip1(M_backend->newVector( M_u_i->map() ));
                    delta_u_ip1->zero();
                    delta_u_ip1->add(1.,M_u_i);
                    delta_u_ip1->add(-1.,u_ip1);

                    vector_ptrtype vectemp(M_backend->newVector( M_u_i->map() ));
                    vectemp->zero();
                    vectemp->add(1., delta_u_i);
                    vectemp->add(-1.,delta_u_ip1);
                    double fact1 = inner_product(vectemp,delta_u_ip1);
                    double fact2 = inner_product(vectemp,vectemp);
                    M_mu = M_mu + ( M_mu - 1)*( fact1 )/( fact2 );

                    M_w = 1 - M_mu;

                }
            else
                {
                    M_w = 1.;
                    M_mu=0.;
                    M_isFirstExperience=false;
                }

            M_u_im1->zero(); M_u_im1->add(1., M_u_i);
            M_u_i->zero(); M_u_im1->add(1., u_ip1);

        }


        double getParameter() { return M_w; }


    private :

        backend_ptrtype M_backend;
        double M_w;
        double M_mu;
        uint M_imax;
        bool M_isFirstExperience;
        vector_ptrtype M_u_i;
        vector_ptrtype M_u_im1;
    };




    inline
    Feel::po::options_description
    makeOptionsNSALE()
    {
        Feel::po::options_description stokesoptions("Stokes options");
        stokesoptions.add_options()
            ("fluide-hsize", Feel::po::value<double>()->default_value( 0.06 ), "h fluide")
            ("struct-hsize", Feel::po::value<double>()->default_value( 0.02 ), "h struct")
            //---------------------------------------------------------------------------------------------//
            ("entree-v", Feel::po::value<double>()->default_value( 1.0 ), "vitesse d entree")
            ("sortie-v", Feel::po::value<double>()->default_value( 1.0 ), "vitesse de sortie")
            ("sortie-p", Feel::po::value<double>()->default_value( 0.0 ), "pression imposee sur la sortie")
            ("entree-p", Feel::po::value<double>()->default_value( 0.0 ), "pression imposee sur l'entree")
            //---------------------------------------------------------------------------------------------//
            ("rho", Feel::po::value<double>()->default_value( 1.0 ), "masse volumique")
            ("mu", Feel::po::value<double>()->default_value( 1.0 ), "reaction coefficient component")
            ("struct-rho", Feel::po::value<double>()->default_value( 1.0 ), "masse volumique")
            ("bccoeff", Feel::po::value<double>()->default_value( 10.0 ), "coeff for weak Dirichlet conditions")
            ("f0", Feel::po::value<double>()->default_value( 0.0 ), "f0")
            ("stab", Feel::po::value<int>()->default_value( 0 ), "0 = Non, 1 = oui")
            ("coef-err", Feel::po::value<double>()->default_value( 1e-5 ), "Coeferr")
            ("mesh", Feel::po::value<std::string>()->default_value( "ola" ), "0 = stationnaire, 1 = instationnaire")
            ("dt", Feel::po::value<double>()->default_value( 0.1 ), "dt")
            ("Tfinal", Feel::po::value<double>()->default_value( 1.0 ), "Temps final")
            ("weakCL", Feel::po::value<bool>()->default_value( false ), "weak CL")
            ("stationnaire", Feel::po::value<bool>()->default_value( false ), "0 = Non, 1 = oui")
            ("movedomain", Feel::po::value<bool>()->default_value( true ), "0 = Non, 1 = oui")
            ("fluide-verbose", Feel::po::value<bool>()->default_value( false ), "0 = Non, 1 = oui")
            ("struct-verbose", Feel::po::value<bool>()->default_value( false ), "0 = Non, 1 = oui")
            ("export", "export results(ensight, data file(1D)")
            ("export-matlab", "export matrix and vectors in matlab" )
            ;
        return stokesoptions.add( Feel::feel_options() ) ;
    }


    /**
     * This routine defines some information about the application like
     * authors, version, or name of the application. The data returned is
     * typically used as an argument of a Feel::Application subclass.
     *
     * \return some data about the application.
     */
    inline
    Feel::AboutData
    makeAboutNSALE()
    {
        Feel::AboutData about( "Fluid-Structure" ,
                               "Fluid-Structure" ,
                               "0.1",
                               "Stokes equation on simplices or simplex products",
                               Feel::AboutData::License_GPL,
                               "Copyright (c) 2009 Universite de Grenoble 1 (Joseph Fourier)");

        about.addAuthor("Vincent Chabannes", "developer", "vincent.chabannes@imag.fr", "");
        return about;

    }


    class Core_Ns_ALE
    {
    public :

        static const int nDim = MECAFLUIDE_DIM;
        static const int nOrder = MECAFLUIDE_ORDER_VELOCITY;

        typedef Application application_type;
        typedef boost::shared_ptr< application_type> application_ptrtype;

        typedef Feel::FSI::NavierStokes<nDim, nOrder, Simplex> NavierStokes_type;
        typedef boost::shared_ptr<NavierStokes_type> NavierStokes_ptrtype;

        typedef Feel::StVenantKirchhoff<nDim, /*nOrder*/2, Simplex> StVenantKirchhoff_type;
        typedef boost::shared_ptr<StVenantKirchhoff_type> StVenantKirchhoff_ptrtype;




        Core_Ns_ALE(int argc, char** argv)
            :
            M_application(new application_type(argc,
                                               argv,
                                               makeAboutNSALE(),
                                               makeOptionsNSALE()
                                               )),
            M_Ti( M_application->vm()["bdf-time-initial"].as<double>() ),
            M_Tf( M_application->vm()["bdf-time-final"].as<double>() ),
            M_dt( M_application->vm()["bdf-time-step"].as<double>() )

            //M_NS_ALE(new NavierStokes_type( M_application ) )
            //M_ModeleStructure(new StVenantKirchhoff_type( M_application ) )
        {

            if ( this->application()->vm().count( "help" ) )
                {
                    std::cout << this->application()->optionsDescription() << "\n";
                    exit(0);//return;
                }

        }


        application_ptrtype application() { return M_application; }

        void run0();
        void run1();
        void run2();
        void run3();
        void run4();
        void run5();
        void run6();

    private :

        application_ptrtype M_application;

        double M_Ti;
        double M_Tf;
        double M_dt;

        //NavierStokes_ptrtype M_NS_ALE;
        //StVenantKirchhoff_ptrtype M_ModeleStructure;

    };

} //end namespace Feel


#endif /* __APPLI_CORE_ALE_NS_H */
